package com.gree.fms.processor.supports;

import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.ListBuffer;
import org.apache.rocketmq.spring.core.RocketMQListener;

import javax.lang.model.element.Element;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author joyce
 */
public class Filters {
    private final static String ABSTRACT_SCOPE = "ABSTRACT";
    private final static String PUBLIC_SCOPE = "PUBLIC";

    public static List<Element> filters(List<Element> classElements, JavacTrees trees) {
        return classElements.stream()
                .filter(classElement -> Objects.isNull(classElement.getModifiers()) ||
                        classElement.getModifiers()
                                .stream()
                                .noneMatch(modifier -> ABSTRACT_SCOPE.equals(modifier.name())))
                .filter(classElement -> Objects.isNull(classElement.getModifiers()) ||
                        classElement.getModifiers()
                                .stream()
                                .anyMatch(modifier -> PUBLIC_SCOPE.equals(modifier.name())))
                .filter(classElement -> Filters.interfaceCheck(classElement, trees))
                .collect(Collectors.toList());
    }

    /**
     * 内部的方法太繁琐了, 所以直接class.ForName
     * @param classElement element
     * @return 是否继承
     */
    private static boolean interfaceCheck(Element classElement, JavacTrees trees ) {
        // 此处不可能为空
        JCTree.JCClassDecl classTree = (JCTree.JCClassDecl)Optional.ofNullable(((JCTree.JCCompilationUnit) trees.getPath(classElement).getCompilationUnit()))
                .map(option -> option.defs)
                .orElseGet(com.sun.tools.javac.util.List::nil)
                .stream()
                .filter(tree -> tree instanceof JCTree.JCClassDecl)
                .findFirst()
                .get();

        // 处理接口和继承
        Type.ClassType classType = (Type.ClassType) classTree.sym.type;
        while (classType != null && classType.tsym != null) {
            classType = (Type.ClassType)classType.tsym.type;
            // 校验接口
            for (Type interfaceType : classType.interfaces_field) {
                if (interfaceType.tsym.getQualifiedName().toString().equals(RocketMQListener.class.getName())) {
                    return true;
                }

                // 处理 super interface
                if (interfaceType instanceof Type.ClassType) {
                    com.sun.tools.javac.util.List<Type> superInterfaceTypes = Optional.ofNullable(((Type.ClassType) interfaceType).all_interfaces_field)
                            .orElse(com.sun.tools.javac.util.List.nil());

                    superInterfaceTypes  = superInterfaceTypes.isEmpty() ?
                            Optional.ofNullable(interfaceType.tsym)
                                    .map(typeSymbol -> ((Type.ClassType)typeSymbol.type).all_interfaces_field)
                                    .orElse(com.sun.tools.javac.util.List.nil()):
                            superInterfaceTypes;

                    ListBuffer<Type> superInterfaceCache = new ListBuffer<>();
                    superInterfaceCache.addAll(superInterfaceTypes);

                    while (!superInterfaceCache.isEmpty()) {
                        superInterfaceTypes = superInterfaceCache.toList();
                        superInterfaceCache.clear();
                        for (Type superInterfaceType : superInterfaceTypes) {
                            // 此处的判断是多此一举的
                            if (superInterfaceType instanceof Type.ClassType) {
                                if (superInterfaceType.tsym.getQualifiedName().toString().equals(RocketMQListener.class.getName())) {
                                    return true;
                                }

                                com.sun.tools.javac.util.List<Type> allInterfacesField = ((Type.ClassType) superInterfaceType).all_interfaces_field;
                                if (allInterfacesField != null && !allInterfacesField.isEmpty()) {
                                    superInterfaceCache.addAll(allInterfacesField);
                                }
                            }
                        }
                    }
                }
            }
            // 处理父类
            if (classType.supertype_field instanceof Type.ClassType) {
                classType = (Type.ClassType)classType.supertype_field;
            } else {
                return false;
            }
        }
        return false;
    }
}
